package git.soulbgm.config;

import git.soulbgm.common.interceptor.RemoteProcedureMethodInterceptor;
import git.soulbgm.common.proxy.RemoteProcedureCallHandler;
import net.sf.cglib.proxy.Enhancer;
import org.springframework.beans.factory.FactoryBean;

import java.lang.reflect.Proxy;

/**
 * @author 贺瑞杰
 * @version V1.0
 * @date 2019-04-08 10:23
 * @description
 */
public class InterfaceFactoryBean<T> implements FactoryBean<T> {

    private Class<T> interfaceClass;

    public Class<T> getInterfaceClass() {
        return interfaceClass;
    }

    public void setInterfaceClass(Class<T> interfaceClass) {
        this.interfaceClass = interfaceClass;
    }

    /*
       Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler handler)方法，
       该方法会根据指定的参数动态创建代理对象。三个参数的意义如下：
       1.loader，指定代理对象的类加载器；
       2.interfaces，代理对象需要实现的接口，可以同时指定多个接口；
       3.handler，方法调用的实际处理者，代理对象的方法调用都会转发到这里（*注意）。

       Proxy.newProxyInstance()会返回一个实现了指定接口的代理对象，对该对象的所有方法调用都会转发给InvocationHandler.invoke()方法
       理解上述代码需要对Java反射机制有一定了解。动态代理神奇的地方就是：
       1.代理对象是在程序运行时产生的，而不是编译期；
       2.对代理对象的所有接口方法调用都会转发到InvocationHandler.invoke()方法，
       在invoke()方法里我们可以加入任何逻辑，比如修改方法参数，加入日志功能、安全检查功能等；
       之后我们通过某种方式执行真正的方法体，比如通过rpc调用远程方法。

       Java动态代理为我们提供了非常灵活的代理机制，但Java动态代理是基于接口的，如果对象没有实现接口我们可以使用CGLIB动态代理。
     */

    @Override
    public T getObject() throws Exception {
        // JDK动态代理
        return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class[]{interfaceClass}, new RemoteProcedureCallHandler());
        // Cglib动态代理
        /*Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(interfaceClass);
        enhancer.setCallback(new RemoteProcedureMethodInterceptor());
        return (T) enhancer.create();*/
    }

    @Override
    public Class<?> getObjectType() {
        return interfaceClass;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}
